home *** CD-ROM | disk | FTP | other *** search
Wrap
/* * This is a text based adventure game which I wrote a number of * years ago (on a unix system), and have since ported to the PC * using MICRO-C. * * With thanks to Crowther and Woods who wrote the original FORTRAN * adventure game from which this game borrows several ideas. * * Copyright 1983-1994 Dave Dunfield * All rights reserved. * * Permission granted for personal (non-commercial) use only. * * Compile command: cc castle -fop */ #include <stdio.h> #define OBJECTS 41 /* number of objects */ #define LOCS 181 /* number of locations */ #define DARK 16 /* first location where its dark */ #define DOORS 14 /* number of doors */ #define MONSTERS 12 /* number of monsters */ #define CARRY 5 /* carry limit */ #define STARTING_HITS 50 /* starting number of hit points */ #define LAMP_DIM_1 250 /* first warning */ #define LAMP_DIM_2 300 /* second warning */ #define LAMP_DIE 350 /* lamp dies */ #define RESUME_TIME 30 /* number of minites before he can resume */ #define EXTRA_POINTS 9 /* extra points for not breaking vase */ /* game status data, all data from 'prop' to start of 'inbuf' (exclusive) */ /* is saved in the file 'castle.sav' when game is suspended */ char prop[OBJECTS] = { 0 }; char door_stat[DOORS]= { 0 }; unsigned location[OBJECTS] = { 6, 4, 39, 8, 77, 33, 18, -1, 21, 24, 29, 92, 64, 108, 10, 144, 146, -1, -1, -1, 31, 67, 115, 65, 105, 79, 141, 41, 42, 117, -1, -1, 96, 12, 90, 163, 128, 124, 11, 135, 164 }; char lstate = 1, died = 0, found_chest = 0; unsigned carry = 0, turns = 0, lturns = 0, current_loc = 1, old_loc = 1, deep = 0; int hits = STARTING_HITS; int monster_hits[] = { /* monsters current hit points */ 10, 20, 25, 30, 40, 55, 60, 60, 75, 50, 100, 100 }; unsigned monster_loc[] = { /* monsters current location */ 15, 25, 41, 55, 69, 83, 97, 111, 125, 139, 153, 167 }; unsigned date[2] = { 0 }; char inbuf[80], *inptr; /* input buffer and pointer */ unsigned places[LOCS]; /* stores pointers to descriptions */ char vocabulary[] = { /* known words */ /* verbs */ 'g','o'+128, 1, 'r','u','n'+128, 1, 'w','a','l','k'+128, 1, 't','a','k','e'+128, 2, 'g','r','a','b'+128, 2, 'g','e','t'+128, 2, 'd','r','o','p'+128, 3, 'd','i','g'+128, 4, 'l','i','g','h','t'+128, 5, 'o','n'+128, 5, 'o','f','f'+128, 6, 'o','p','e','n'+128, 7, 'u','n','l','o','c','k'+128,7, 'm','o','v','e'+128, 7, 'p','u','s','h'+128, 7, 'r','e','m','o','v','e'+128,7, 'c','l','o','s','e'+128, 8, 'l','o','c','k'+128, 8, 'l','o','o','k'+128, 9, 'v','i','e','w'+128, 9, 'i','n','v','e','n','t','o','r','y'+128, 10, 'c','a','r','r','y'+128, 10, 'q','u','i','t'+128, 11, 's','t','o','p'+128, 11, 'r','e','a','d'+128, 12, 'w','a','v','e'+128, 13, 'r','u','b'+128, 13, 'o','p','e','r','a','t','e'+128, 13, 'u','s','e'+128, 13, 'a','b','r','a','c','a','d','a','b','r','a'+128, 14, 'h','o','k','u','s'+128,14, 'p','o','k','u','s'+128,14, 's','e','s','a','m','e'+128,14, 's','h','a','z','a','m'+128,14, 'p','l','u','g','h'+128, 14, 'x','y','z','z','y'+128, 14, 'f','a','r','l','e','y'+128,15, 's','u','s','p','e','n','d'+128,16, 'r','e','s','u','m','e'+128,17, 'a','t','t','a','c','k'+128,18, 's','w','i','n','g'+128, 18, 's','t','a','b'+128, 18, 't','h','r','u','s','t'+128,18, 'k','i','l','l'+128, 18, 'h','i','t'+128, 18, 'd','r','i','n','k'+128, 19, 'e','m','p','t','y'+128, 20, 'd','u','m','p'+128, 20, 's','p','i','l','l'+128, 20, 'r','e','t','r','e','a','t'+128,21, 'b','a','c','k','u','p'+128,21, 'l','a','s','t'+128, 21, 'b','a','c','k'+128, 21, 'o','u','t'+128, 21, 'o','i','l'+128, 22, 'l','u','b','r','i','c','a','t','e'+128,22, 's','c','o','r','e'+128, 23, 'p','o','i','n','t','s'+128,23, 's','h','i','t'+128, 24, 'f','u','c','k'+128, 24, 'd','a','m','n'+128, 24, 'p','i','s','s'+128, 24, /* nouns */ 'g','a','t','e'+128, 50, 'g','r','a','t','e'+128, 50, 'f','e','n','c','e'+128, 50, 'd','o','o','r'+128, 50, 's','l','a','b'+128, 50, 's','i','g','n'+128, 50, 'b','o','o','k','c','a','s','e'+128, 50, 's','h','e','l','v','e','s'+128, 50, 's','h','e','l','f'+128, 50, 'b','a','r','s'+128, 50, 'c','e','l','l'+128, 50, 'p','i','t'+128, 51, 'h','o','l','e'+128, 51, 's','t','a','i','r','s'+128,52, 'l','a','d','d','e','r'+128,52, 'w','a','l','l'+128, 53, 'c','a','v','e'+128, 53, 'c','a','v','e','r','n'+128,53, 'g','r','o','u','n','d'+128,53, 'f','l','o','o','r'+128, 53, /* objects */ 'l','a','m','p'+128, 100, 'l','a','n','t','e','r','n'+128,100, 'k','e','y'+128, 101, 'r','o','p','e'+128, 102, 's','t','r','i','n','g'+128,102, 'c','o','r','d'+128, 102, 'k','n','i','f','e'+128, 103, 'd','a','g','g','e','r'+128,103, 'a','x','e'+128, 104, 'h','a','t','c','h','e','t'+128,104, 's','w','o','r','d'+128, 105, 'h','i','l','t'+128, 105, 's','a','c','k'+128, 106, 'b','a','g'+128, 106, 'b','a','t','t','e','r','i','e','s'+128,107, 'b','a','t','t','e','r','y'+128,107, 'b','a','r'+128, 108, 'c','r','o','w','b','a','r'+128,108, 'r','o','d'+128, 109, 'w','a','n','d'+128, 109, 's','c','r','o','l','l'+128,110, 'p','a','p','e','r'+128, 110, 'r','o','l','l'+128, 110, 'p','o','t','i','o','n'+128,111, 'b','o','t','t','l','e'+128,111, 'f','l','a','s','k'+128, 112, 'l','i','q','u','i','d'+128,112, 'v','e','l','v','e','t'+128,113, 'p','i','l','l','o','w'+128,113, 'r','o','c','k'+128, 114, 's','t','o','n','e'+128, 114, 'p','u','r','p','l','e'+128,114, 'c','a','n','n','o','n'+128,115, 'b','a','l','l'+128, 115, 'm','e','t','a','l'+128, 116, 'd','e','t','e','c','t','o','r'+128,116, /* treasure objects */ 'c','o','i','n','s'+128, 120, 'm','o','n','e','y'+128, 120, 'r','i','n','g'+128, 121, 'b','a','n','d'+128, 121, 's','t','a','t','u','e'+128,122, 'c','r','y','s','t','a','l'+128,122, 'd','r','a','g','o','n'+128,122, 'i','v','o','r','y'+128, 123, 'a','m','u','l','e','t'+128,123, 'e','b','o','n','y'+128, 124, 'g','l','o','b','e'+128, 124, 'c','r','o','w','n'+128, 125, 'd','i','a','m','o','n','d'+128,126, 'g','o','l','d'+128, 127, 'n','u','g','g','e','t'+128,127, 'n','u','g','g','e','t','s'+128,127, 'p','r','e','c','i','o','u','s'+128,128, 'j','e','w','e','l','s'+128,128, 'j','e','w','e','l','r','y'+128,128, 'p','l','a','t','i','n','u','m'+128,129, 'p','y','r','a','m','i','d'+128,129, 'c','h','e','s','t'+128, 130, 't','r','e','a','s','u','r','e'+128,130, 'e','m','e','r','a','l','d'+128,131, 'e','a','r','r','i','n','g'+128,131, 'r','a','r','e'+128, 132, 's','p','i','c','e'+128, 132, 's','p','i','c','e','s'+128,132, 'p','e','r','s','i','a','n'+128,133, 'r','u','g'+128, 133, 'r','u','b','y'+128, 134, 's','t','a','f','f'+128, 134, 'm','i','n','g'+128, 135, 'v','a','s','e'+128, 135, 's','i','l','v','e','r'+128,136, 'p','e','n','d','a','n','t'+128,136, 'p','a','i','n','t','i','n','g'+128,137, 'a','r','t'+128, 137, 'b','r','o','n','z','e'+128,138, 'c','a','n','d','l','e'+128,138, 'c','a','n','d','l','e','s','t','i','c','k'+128,138, 's','i','l','k'+128, 139, 'j','a','c','k','e','t'+128,139, 's','i','l','k','e','n'+128,139, 'c','o','a','t'+128, 139, 'b','o','o','k'+128, 140, 'b','i','b','l','e'+128, 140, 'l','e','a','t','h','e','r'+128, 140, /* directions */ 'n','o','r','t','h'+128, 240, 'n'+128, 240, 'e','a','s','t'+128, 241, 'e'+128, 241, 's','o','u','t','h'+128, 242, 's'+128, 242, 'w','e','s','t'+128, 243, 'w'+128, 243, 'u','p'+128, 244, 'u'+128, 244, 'd','o','w','n'+128, 245, 'd'+128, 245, /* filler words, not actually looked at, but no message given is used */ 's','a','y'+128, 0, 't','h','e'+128, 0, 'a'+128, 0, 'w','i','t','h'+128, 0, 't','u','r','n'+128, 0, 'a','t'+128, 0, 0 }; /* door descriptions: "closed desc|open desc" */ char *doors[] = { "The grate is locked|The grate is open", "A large bookcase fills the east wall|A large bookcase is standing beside a small exit in the east wall", "The door is locked shut|The door is open", "A massive stone slab leans against the west wall|A massive stone slab stands beside a passage leading west", "The fissure is too wide to cross|A solid stone bridge crosses the fissure", "The trapdoor is locked|The trapdoor is open", "The sign is firmly fastened to the wall|The sign stands beside a small passage", "The door is locked|The door is open", "The hinges on the door are rusted solid|The door is open", "The door is tightly locked|The door is standing open", "The north wall is filled with sturdy shelves|A small passage exits from the north wall, beside a pile of rubble", "The bars are locked shut|The bars are open", "The bars are locked shut|The bars are open", "The bars are locked shut|The bars are open" }; /* table of objects required to open the doors */ char door_keys[DOORS] = { 1, 8, 1, 8, 0, 1, 8, 1, 0, 1, 8, 1, 1, 1 }; /* table of damage done by weapons */ char damage[3] = { 10, 18, 34 }; /* long object descriptions, Multiple descriptions (Seperated by '|') are */ /* for different prop values of the object (Starting with prop value=0). */ /* Last desc is given if the prop value is higher than # of descrptions. */ char *l_descriptions[] = { "An unlit brass lantern is here|A brightly glowing brass lantern is here|A dimly glowing brass lantern is here|A very dim brass lantern is here", "There is a small key on the ground here", "There is a long length of rope here", "A small sharp knife is on the ground nearby", "A little axe is lying on the ground here", "The hilt of a shining sword protrudes from the stone|There is a long shiny sword here", "A large brown sack is lying in a heap on the floor", "There are fresh batteries here|Some old worn-out batteries are discarded nearby", "A long crowbar is lying on the ground here", "There is a long black rod with a rusty star on its end here", "A tightly rolled paper scroll is here|A blank sheet of paper is here", "There is a small bottle here, containing a golden potion|A small empty bottle is discarded nearby", "There is a small flask full of a dark liquid here|A small empty flask is discarded nearby", "A soft velvet pillow is resting on the floor here", "A funny looking purple stone is lying on the ground here", "There is a large black cannon ball here", "A battered metal detector is lying on the ground here", /* objects 17 through 19 reserved for future non-valuable items */ "", "", "", /* objects 20 and above represent treasure items. */ "There is a pile of coins on the ground here", "A small golden ring is lying on the ground here", "There is a small crystal statue of a dragon here", "A small ivory amulet is lying to one side", "A small globe of ebony is resting on the floor here", "There is a many jeweled crown here", "A large sparkling diamond is here", "There are nuggets of gold here", "There is precious jewelry here", "There is a platinum pyramid here, eight inches to a side", "The thiefs treasure chest is here", "A large emerald earring is lying on the ground here", "There are rare spices here", "A valuable persion rug is spread out on the floor", "A ruby studded staff is lying on the ground here", "A precious ming vase is resting delicately here|The floor is littered with worthless shards of pottery", "There is a large silver pendant lying here", "A beautiful painting is lying against the wall", "There is a beautiful bronze candlestick here", "There is a lovely silken jacket here", "A rare leather bound bible is lying on the ground here" } ; /* short object descriptions, format same as above */ char *s_descriptions[] = { "Brass lantern|Brightly shining brass lantern|Dim brass lantern|Very dim brass lantern", "Small key", "Coil of rope", "Small sharp knife", "Little axe", "Long shiny sword", "Large sack", "Fresh batteries|Worn-out batteries", "Long crowbar", "Long black rod", "Paper scroll|Blank paper scroll", "Bottle containing golden potion|Empty bottle", "Flask containing dark liquid|Empty flask", "Velvet pillow", "Purple stone", "Cannon ball", "Metal detector", /* objects 17 through 19 reserved for future non-valuable items */ "", "", "", /* valuable "treasure" objects */ "Many coins", "Small golden ring", "Crystal statue", "Ivory amulet", "Ebony globe", "Jeweled crown", "Sparkling diamond", "Gold nuggets", "Precious jewelry", "Platinum pyramid", "Treasure chest", "Emerald earring", "Rare spices", "Persion rug", "Rubby studded staff", "Ming vase|Broken vase", "Silver pendant", "Beautiful painting", "Bronze candlestick", "Silken jacket", "Rare bible" } ; /* Travel table, each entry corresponds to a location in the game, */ /* and has six words, each representing a direction (North, East, */ /* South, West, Up, Down). Bits 0-7 of each word represents a new */ /* location that can be reached by that direction. Bits 8-12 give */ /* a number 'N' which is used in conditional movement calculations */ /* Bits 13-15 give the type of conditional movement as follows: */ /* 0 - Unconditional, character moves directly to new location. */ /* 1 - Door 'N' must be open, otherwise describe the door. */ /* 2 - He must be carrying object 'N'. */ /* 3 - He must not be carrying object 'N' */ /* 4 - Object 'N' must have prop value = 0. */ /* 5 - Object 'N' must have prop value = 1. */ /* 6 - Special condition 'N', (See "special_condition") */ /* 7 - Special action 'N' occurs when passed (See "special_action") */ unsigned travel[LOCS][6] = { /* N, E, S, W, U, D */ 0, 0, 0, 0, 0, 0, 5, 0, 2, 6, 0, 0, 1, 2, 2, 3, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 3, 0, 7, 8, 1, 6, 0, 0, /* 5 */ 7, 5, 1, 7, 0, 0, 7, 7, 5, 7, 0, 0, 7, 7, 9, 5, 0, 0, 8, 7, 7, 7, 0, 0x200f, 105, 0, 0, 0xc068, 0, 0, /* 10 */ 0, 0, 126, 0, 0, 0, 164, 0, 163, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 16, 17, 25, 0x2009, 0, /* 15 */ 0, 0x211e, 0, 15, 0, 0, 15, 19, 0, 18, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 20, 17, 0, 0, 19, 0, 21, 22, 0, 0, /* 20 */ 20, 0, 0, 0, 0, 0, 0, 20, 0, 23, 0, 0, 24, 22, 0, 0, 0, 0, 25, 0, 23, 0, 0, 0, 31, 15, 24, 0, 0, 0, /* 25 */ 27, 0, 15, 0, 0, 0, 0x221c, 0, 26, 0, 0, 0, 0, 29, 0x221b, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 16, 0, 32, /* 30 */ 0, 0, 25, 0, 0, 0, 33, 0, 0, 0, 30, 0, 34, 0, 44, 32, 0, 0, 38, 40, 33, 0x2323, 0, 0, 36, 34, 0, 0, 0, 0, /* 35 */ 0, 37, 35, 0, 0, 0, 0, 0, 0, 36, 0, 61, 0, 39, 34, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 42, 0x6629, 34, 0x6629, 0, /* 40 */ 40, 0, 0, 0, 0, 0, 0, 43, 0, 40, 0, 0, 0, 42, 0, 0, 0, 0, 0, 45, 0, 33, 0, 0, 0, 46, 48+0xe000, 44, 0, 0, /* 45 */ 0, 47, 0, 45, 0, 0, 0, 0, 0, 46, 0, 0, 56+0xe000, 55+0xe000, 53+0xe000, 49+0xe000, 45, 52+0xe000, 50+0xe000, 49+0xe000, 48+0xe000, 49+0xe000, 57+0xe000, 51+0xe000, 51+0xe000, 54+0xe000, 53+0xe000, 56+0xe000, 58+0xe000, 50+0xe000, /* 50 */ 49+0xe000, 55+0xe000, 54+0xe000, 50+0xe000, 57+0xe000, 57+0xe000, 48+0xe000, 56+0xe000, 55+0xe000, 49+0xe000, 54+0xe000, 52+0xe000, 50+0xe000, 57+0xe000, 54+0xe000, 59+0xe000, 58+0xe000, 48+0xe000, 57+0xe000, 54+0xe000, 49+0xe000, 52+0xe000, 57+0xe000, 56+0xe000, 54+0xe000, 56+0xe000, 59+0xe000, 52+0xe000, 53+0xe000, 51+0xe000, /* 55 */ 48+0xe000, 57+0xe000, 52+0xe000, 53+0xe000, 58+0xe000, 50+0xe000, 56+0xe000, 49+0xe000, 53+0xe000, 51+0xe000, 54+0xe000, 52+0xe000, 54+0xe000, 56+0xe000, 48+0xe000, 55+0xe000, 55+0xe000, 50+0xe000, 58+0xe000, 55+0xe000, 57+0xe000, 52+0xe000, 60, 53+0xe000, 0, 0, 0, 0, 0, 59+0xe000, /* 60 */ 0, 0, 62, 0, 37, 0, 61, 63, 0, 71, 0, 0, 64, 66, 0xe243, 62, 0, 0, 0, 0, 63, 0, 0x6641, 0, 0, 0, 0, 0, 0, 64, /* 65 */ 0, 0, 68, 63, 0, 0, 0xe23f, 68, 0, 0, 0, 0, 66, 0, 69, 67, 0, 0, 0, 68, 0x5749, 70, 0, 0, 71, 0, 69, 80+0xe000, 0, 0, /* 70 */ 72, 62, 70, 0, 0, 0, 0, 0, 71, 0, 0, 0xc258, 69, 0, 0x574a, 0, 0, 0, 0x5749, 0, 0x574b, 0x574c, 0, 0, 0x574a, 0x574e, 0, 0x574c, 0, 0, /* 75 */ 0x574a, 0x574b, 0x574d, 0, 0, 0, 0x574c, 0x574e, 0x584f, 0, 0, 0, 0x574b, 0, 0x584f, 0x574d, 0, 0, 0, 78, 0, 77, 0, 0, 81+0xe00, 81+0xe00, 83+0xe00, 85+0xe00, 84+0xe00, 70, /* 80 */ 83+0xe00, 82+0xe00, 80+0xe00, 86+0xe00, 85+0xe00, 81+0xe00, 82+0xe00, 85+0xe00, 80+0xe00, 81+0xe00, 86+0xe00, 84+0xe00, 85+0xe00, 83+0xe00, 82+0xe00, 84+0xe00, 83+0xe00, 83+0xe00, 83+0xe00, 84+0xe00, 84+0xe00, 82+0xe00, 83+0xe00, 84+0xe00, 85+0xe00, 81+0xe00, 82+0xe00, 86+0xe00, 82+0xe00, 81+0xe00, /* 85 */ 86+0xe00, 82+0xe00, 84+0xe00, 83+0xe00, 83+0xe00, 87, 0, 0, 0, 0, 86+0xe00, 0, 0, 0, 89, 0x245f, 72, 0, 88, 90, 91, 0, 0, 0, 0, 0, 0, 89, 0, 0, /* 90 */ 89, 92, 93, 0, 0, 0, 0, 0, 0, 91, 0, 0, 91, 94, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0x2458, 97, 96, 0, 0, /* 95 */ 0, 95, 0, 0, 0, 0, 95, 0, 98, 0, 0, 0, 97, 0, 100, 99, 0, 0, 0, 98, 0, 0, 0, 0x2565, 98, 0, 0, 0, 0, 0, /* 100 */ 0, 102, 0, 0, 0x2563, 0, 112, 0, 103, 101, 0, 0, 102, 104, 0, 106, 0, 0, 0, 0xc00a, 0, 103, 0, 0, 0, 0, 10, 0, 0, 0, /* 105 */ 0, 103, 107, 0, 0, 0, 106, 0, 0xe26c, 109, 0, 0, 0, 0xe26b, 0, 109, 0, 0, 110, 107, 108, 0, 0, 0, 116, 111, 109, 120, 0, 0, /* 110 */ 118, 112, 0, 110, 0, 0, 0, 113, 102, 111, 0, 0, 114, 0, 0, 112, 0, 0, 0, 115, 113, 116, 0, 0, 0, 0, 0, 114, 0, 0, /* 115 */ 0x2675, 114, 110, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0xe077, 0, 111, 0, 0, 0, 0xe177, 0xe177, 0xc176, 0xe177, 0xe177, 0xe177, 121, 110, 0, 0, 0, 0, /* 120 */ 0, 0, 120, 0, 0, 122, 0, 123, 131, 0, 121, 0, 0, 125, 0x287c, 122, 0, 0, 123, 0, 0, 0, 0, 0, 126, 0, 132, 123, 0, 0, /* 125 */ 11, 0, 125, 127, 0, 0, 128, 126, 0, 129, 0, 0, 0, 0, 127, 0, 0, 0, 127, 0, 131, 130, 0, 0, 129, 0, 133, 0, 0, 0, /* 130 */ 122, 0x2787, 0xe285, 129, 0, 0, 125, 0, 133, 0, 0, 0, 0xe283, 132, 134, 130, 0, 0, 133, 0, 0, 0, 0, 136, 0, 0, 0, 0x2783, 0, 0, /* 135 */ 137, 0, 0, 0, 134, 0, 138, 0, 136, 0, 0, 0, 0, 139, 137, 144, 0, 0, 140, 0, 0, 138, 0, 0, 142, 0, 139, 141, 0, 0, /* 140 */ 0, 140, 0, 0, 0, 0, 0, 0, 140, 143, 0, 0, 0x2994, 142, 0, 147, 0, 0, 145, 138, 0, 0, 0, 0, 147, 146, 144, 0, 0, 0, /* 145 */ 0x2a95, 0, 0, 145, 0, 0, 0, 143, 145, 0, 0, 0, 0, 0, 0x298f, 0, 0, 0, 0, 0, 146, 0, 0, 150, 0, 0, 151, 0, 149, 0, /* 150 */ 150, 152, 0, 160, 0, 0, 151, 0x2b9b, 153, 0, 0, 0, 152, 0x2c9c, 154, 0, 0, 0, 153, 0x2d9d, 158, 0, 0, 0, 0, 0, 0, 0x2b98, 0, 0, /* 155 */ 0, 0, 0, 0x2c99, 0, 0, 0, 0, 0, 0x2d9a, 0, 0, 0, 154, 159, 160, 0, 0, 158, 0, 0, 0, 0, 0, 151, 0, 158, 161, 0, 0, /* 160 */ 162, 160, 168, 163, 0, 0, 0, 0, 161, 0, 0, 0, 12, 161, 0, 166, 0, 0, 0, 0, 12, 0, 0, 0, 0, 12, 166, 0, 0, 0, /* 165 */ 165, 163, 167, 169, 0, 0, 166, 168, 0, 0, 0, 0, 161, 0, 0, 167, 0, 0, 170, 166, 173, 171, 0, 0, 0, 0, 169, 177, 0, 0, /* 170 */ 0, 169, 0, 172, 0, 0, 178, 171, 175, 0, 0, 0, 169, 0, 0, 174, 0, 0, 0, 173, 0, 175, 0, 0, 172, 174, 0xe3b0, 0, 0, 0, /* 175 */ 175, 0, 0, 0, 0, 0, 0, 170, 0, 178, 0, 0, 0, 177, 172, 179, 0, 0, 0, 178, 0, 180, 0, 0, 0, 179, 0, 0, 0, 0 /* 180 */ } ; /* death messages, issued for the three times he is allowed to die */ char *diemsgs[] = { "Oh dear.. You seem to have gotten yourself killed!\nI might be of some assistance although I have never actually done this before.\nWould you like me to try and re-incarnate you", "Clumsy oaf, you've done it again...\nI don't know how long I can keep this up!\nWould you like me to try again to re-incarnate you", "Now you've REALLY done it!!!\nIm all out of orange smoke!!!\nYou don't expect me to do a decent re-incarnation\nwithout orange smoke do you" } ; /* snide comments as we resurrect him. */ char *resmsgs[] = { "All right, but don't blame me if something goes wrong...\n((( POOF!!! )))\nYou are engulfed in a cloud of bright orange smoke...\nYou emerge to find...", "Ok... Now where did I put my orange smoke...\n((( POOF!!! )))\nEverything disappears in a dense cloud of orange smoke", "If you're so smart.. do it yourself... Im leaving." } ; /* descriptions of live (or at least moveing) monsters */ char *monsters[] = { "There is a nasty looking skeleton attacking you!", "There is a nasty big orc in the room with you!", "A wicked little goblin is in the room with you!", "There is a fearsome bugbear in the room with you!", "A huge lizard-man is here in the room with you!", "There is a fearsome looking ogre in the room with you!", "There is a wretched looking mummy attacking you!", "A large suit of armor is attacking you", "A huge big giant is trying to kill you!", "Near the edge of you vision, a slight movement attracts your attention!", "A awful *DRAGON* is here in the room, he dosn't look friendly", "A little man in a long flowing robe is looking at you" }; /* description of monsters attacking */ char *monster_attack[] = { "The skeleton lunges at you!", "The orc swings at you with a nasty long sword!", "The goblin thrusts at you with a sharp spear!", "The bugbear claws and bites at you!", "The lizard-man snaps at you!", "The ogre bashes at you with a giant club!", "The mummy howls, and lunges at you!", "The suit of armour swings a fearsome sword!", "The giant clobbers at you with its huge fists!", "You hear the swoosh of a dagger behind your back!", "The *DRAGON* breathes fire.... Wow is it getting warm in here!!!", "The wizard waves his hands, and pronounces a spell!" }; /* descriptions of deceased monsters */ char *dead_monster[] = { "A shattered pile of bones is lying to one side.", "A dead orc is lying here.", "A dead goblin is lying to one side.", "The body of a dead bugbear is peacefully resting here.", "The body of a lizard-man is lying here.", "A huge ugly nasty horrible dead ogre is lying on the ground here.", "A pile of cloth and bones is lying to one side.", "Pieces of broken armor litter the floor.", "The body of a huge giant is partially blocking the passage.", "A dead small elvish humanoid is here, wearing a small black mask.", "The body of a huge dead dragon is nearly blocking the passage.", "A small pile of ashes and a wizard's hat are lying here." }; /* names of monsters */ char *monster_short[] = { "skeleton", "orc", "goblin", "bugbear", "lizard-man", "ogre", "mummy", "suit of armor", "giant", "thief", "dragon", "wizard" }; unsigned monster_start[] = { /* highest place monster can go */ 15, 32, 32, 61, 61, 88, 101, 122, 122, 32, 137, 150 }; /* rank messages */ char *ranks[] = { "You are obviously a rank amateur. Better luck next time.", "Your score qualifies you as a novice class adventurer.", "You have acheived the rateing 'Experienced Adventurer'.", "You may now consider yourself a 'Seasoned Adventurer'.", "You have reached 'Junior Master' status.", "You now rate as a master adventurer class D.", "You now rate as a master adventurer class C.", "You now rate as a master adventurer class B.", "You now rate as a master adventurer class A.", "All adventuredom gives tribute to you, 'Adventurer Grandmaster'." }; /* misc. common messages */ char can_not_move[] = "You can not move in that direction." ; char too_big[] = "Something your carrying won't fit through the passage." ; char *dirptr = 0 ; unsigned seed; /* Random number seed */ FILE *fp, *fp1; main(argc, argv) int argc; char *argv[]; { unsigned words[10], i, j, verb, noun, door, temp; if(argc > 1) dirptr = argv[1]; /* initialize random number seed */ get_time(&i, &j, &temp); seed = (j*1000) + (i*60) + temp; message("ADVENTURE CASTLE by Dave Dunfield\n"); /* get help if any */ get_line("Welcome adventurer, would you like instruction?"); if(*inptr == 'y') { fp1 = fileopen("castle.hlp","rvq"); while((i = getc(fp1)) != EOF) putc(i, stdout); fclose(fp1); } /* initializations */ message("One moment please..."); read_data_file("castle.dat"); putc('\n',stdout); look(current_loc); for(;;) { if(current_loc > deep) deep = current_loc; get_line(">"); temp=0; while(*inptr) if(words[temp] = parse()) ++temp; words[temp] = 0; verb = noun = 0; for(i = 0; i< temp; ++i) { if((words[i] < 50) && (words[i] > verb)) verb = words[i]; if(words[i] > 49) noun = words[i]; } if((!verb) && (noun > 239)) /* assume GO */ verb = 1; door = -1; for(i=0; i<6; ++i) if((travel[current_loc][i] >> 13) == 1) door = (travel[current_loc][i] >> 8) & 0x1f; /* figgure out what he wants */ switch(verb) { case 1 : /* movement */ if(noun < 240) message("Give me a direction."); else move(noun - 240); break; case 2 : /* take an object */ if((noun < 100) && (noun > 49)) message("You can't move it."); else if((noun = isobject(noun)) != -1) { if(!location[noun]) message("Your already carrying it!"); else if(location[noun] != current_loc) message("I don't see it here."); else if(carry >= (CARRY + (5*(location[6] == 0)))) message("You can't carry anything more, you will have to drop something first."); else if((noun == 5) && (!prop[noun])) message("The sword is stuck quite firmly, you can't budge it!"); else { location[noun] = 0; ++carry; if(noun == 30) found_chest = -1; ok(); } } break; case 3 : /* drop an object */ if((noun = isobject(noun)) != -1) { if(location[noun]) message("You are not carrying it!"); else if((noun == 6) && (carry > CARRY)) message("You need it to carry some of the other stuff!"); else { location[noun] = current_loc; --carry; ok(); if((current_loc == 60) && (noun == 20)) { location[noun] = 148; /* remove coins to supply room */ if(!location[7]) /* he's carrying old batteries */ --carry; location[7] = current_loc; /* give him batteries */ prop[7] = 0; /* insure they are fresh */ message("There are fresh batteries here!"); } if((noun == 35) && (location[13] != current_loc)) { prop[35] = 1; message("The vase drops with a delicate crash!"); } } } break; case 4 : /* dig */ message("Digging without a shovel is impractical, progress seems unlikely."); break; case 5 : /* light lamp */ if(test_range(noun,100,100)) { if(have_object(0)) { if(prop[0]) message("Its already on."); else { if((!lstate) && (!prop[7]) && (ishere(7))) { lstate = prop[7] = 1; lturns = 0; message("I'm takeing the liberty of changing the batteries."); } if(prop[0] = lstate) { ok(); if(current_loc >= DARK) look(current_loc); } else message("The batteries are dead."); } } } break; case 6 : /* turn off lamp */ if(test_range(noun,100,100)) { if(have_object(0)) { if(!prop[0]) message("Its already off."); else { prop[0] = 0; ok(); if(current_loc >= DARK) look(current_loc); } } } break; case 7 : /* open a door */ if(test_range(noun, 50, 50)) { if(door == -1) not_here(); else { if((temp=door_keys[door]) && (!location[temp])) { door_stat[door] = 1; ok(); } else message("You can't, I think you will need something to do that."); } } break; case 8 : /* close a door */ if(test_range(noun, 50, 50)) { if(door == -1) not_here(); else { if((temp=door_keys[door]) && (!location[temp])) { door_stat[door] = 0; ok(); } else message("You can't, I think you will need something to do that."); } } break; case 9 : /* look around */ message("I will repeat the description of your location:"); look(current_loc); break; case 10 : /* inventory */ message("You are currently carrying the following:"); for(i=0; i<OBJECTS; ++i) if(!location[i]) describe(i,s_descriptions); break; case 11 : /* quit */ get_line("Do you really want to quit now?"); if('y' == *inptr) end_game(); ok(); break; case 12 : /* read */ if(noun == 110) { /* scroll */ if(have_object(10)) if(prop[10]) message("Im afraid the paper is blank"); else if(ishere(21) && (current_loc == 33)) { prop[10] = prop[5] = 1; message("As you pronounce the archane words, the sword jumps as if alive,\nand falls at your feet."); } else { prop[10] = 1; message("As you attempt to pronounce the strange words on the scroll,\nThe ink disappears in a wisp of orange smoke."); } } else message("I don't know how to read that!"); break; case 13 : /* wave, rub, etc */ if((noun = isobject(noun)) != -1) { if(have_object(noun)) if((noun == 9) && ((current_loc == 88) || (current_loc == 95))) { if(door_stat[4]) { door_stat[4] = 0; message("The stone bridge has vanished!"); } else { door_stat[4] = 1; message("A stone bridge now spans the fissure!"); } } else if(noun == 16) { message("Crackle... Buzz... Humm...."); if((current_loc == 6) && (location[31] == -1)) { message("BEEP BEEP BEEP: Detected something"); location[31] = current_loc; } else message("No metal here"); } else message("Nothing exciting happens."); } break; case 14 : message("Good try.... but thats on old worn-out magic word."); break; case 15 : /* magic word */ old_loc = 0; if((current_loc == 16) || (current_loc == 133)) look(current_loc = 4); else if(current_loc == 4) look(current_loc = 16); else if(current_loc == 102) look(current_loc = 10); else if(current_loc == 10) look(current_loc = 102); else message("Nothing unusual happens."); break; case 16 : /* suspend game */ if(fp1 = fopen("castle.sav","wbv")) { fwrite(prop, (date - prop) + 4, fp1); fclose(fp1); message("Game saved..."); end_game(); } break; case 17 : /* resume game */ if(!turns) { if(fp1 = fopen("castle.sav","rbv")) { fread(prop, (date - prop) + 4, fp1); fclose(fp1); } look(current_loc); } else message("You can only resume at the start of a game"); break; case 18 : /* attack */ if(test_range(noun,103,105)) { if(!location[noun - 100]) { noun -= 103; temp = 0; message("You take a wild swing..."); for(i=0; i < MONSTERS; ++i) { if(monster_loc[i] == -1) { ++temp; if(random() > (8000 - (noun*1500))) { printf("and hit the %s!\n",monster_short[i]); if((monster_hits[i] -= damage[noun]) <= 0) { monster_loc[i] = current_loc; message("You killed it!!!"); } } } } if(!temp) message("but your blade meets only air, be carefull not to hurt yourself!"); } else message("You don't have that weapon."); } break; case 19 : /* drink */ if(test_range(noun,111,112) && have_object(noun-100)) if(noun == 111) if(!prop[11]) { /* bottle */ ++prop[11]; hits = STARTING_HITS; message("That was quite refreshing, you feel stronger."); } else message("The bottle is empty."); else if(!prop[12]) { /* flask */ ++prop[12]; message("That was awful... I don't feel well!"); if((hits -= 15) <= 0) die(); } else message("The flask is empty."); break; case 20 : /* empty */ if(test_range(noun,111,112) && have_object(noun = noun-100)) if(!prop[noun]) { ++prop[noun]; ok(); } else message("It's already empty."); break; case 21 : /* backup */ if((!old_loc) || (old_loc == current_loc)) message("I can't quite seem to remember how it was we got here!"); else look(current_loc = old_loc); break; case 22 : /* lubricate */ if(test_range(noun,50,50)) { if(!ishere(12)) message("You have no oil!"); else if(prop[12]) message("The oil flask is empty!"); else if(door == -1) not_here(); else { ++prop[12]; if(current_loc == 123) { /* castle door */ ++door_stat[8]; message("As you lubricate the hinges, the door slowly creaks open!"); } } } break; case 23 : /* score, points etc. */ printf( "If you quit now, you will have a score of %u points.\n", calculate_score()); break; case 24 : /* bad words */ message("Watch your language!!!"); #ifdef DEBUG printf("[%u], ", current_loc); get_line("New?"); look(current_loc = atoi(inptr)); #endif break; default : message("I don't quite understand you."); } ++turns; /* check the status of the lamp */ if(prop[0]) { /* lamp is on */ if((LAMP_DIM_1 <= ++lturns) && (!location[7]) && (ishere(0)) && (!prop[7])) { /* time to change batteries */ prop[7] = prop[0] = lstate = 1; /* take away new batteries, brighten lamp */ lturns = 0; /* insure we don't go dim again */ message("You lamp is going dim, Im takeing the liberty of changing the batteries."); } else if(lturns == LAMP_DIM_1) { prop[0] = lstate = 2; if(ishere(0)) { message("Your lamp is growing dim... You should wrap this up soon, unless you"); message("can find some fresh batteries. I seem to recall there is a vending"); message("machine in the maze, bring some coins with you"); } } else if(lturns == LAMP_DIM_2) { prop[0] = lstate = 3; if(ishere(0)) message("You lamp is getting dimmer... You'd best get those batteries soon!"); } else if(lturns == LAMP_DIE) { prop[0] = lstate = 0; if(ishere(0)) message("Your lamp has run out of power."); } } if((isdark(current_loc)) && (8000 > random()) && (verb == 1)) { message("You fell into a pit... OUCH!!! ... That hurt!"); if((hits -= 10) <= 0) { die(); } } /* check for wandering monsters */ for(i=0; i < MONSTERS; ++i) { if((monster_loc[i] == current_loc) && (monster_hits[i] > 0)) monster_loc[i] = -1; if(monster_loc[i] == -1) { if(current_loc >= DARK-1) { message(monsters[i]); temp = random(); if(temp < 1000) { /* monster runs off */ monster_loc[i] = current_loc + 1; message("It ran off!"); } else if(temp < 23000) { /* monster attacks */ j = OBJECTS; if((i == 9) && (!found_chest)) { /* thief */ while(--j > 19) { if(ishere(j)) { monster_loc[9] = location[30] = location[j] = 87; --carry; j = 1; /* only take one */ temp = 32767; /* insure no attack */ message("A thief stole a treasure and ran off!"); } } } if(j) message(monster_attack[i]); if(temp < 12000) { /* monster hits */ message("It hits you..."); if((hits -= (i+2)) <= 0) { i = MONSTERS; /* don't attack if DIE returns */ die(); } else message("OUCH!!! ... That hurt!!!"); } } } } else { /* monster is not in room */ if(monster_hits[i] > 0) if(LOCS <= ++monster_loc[i]) monster_loc[i] = monster_start[i]; } } } } /* skip ahead to next non-blank */ char skip_blank() { while(*inptr == ' ') ++inptr; return *inptr; } /* test for terminator character */ isterm(chr) char chr; { return (chr == ' ') | (chr == 9) | (chr == 0); } /* pick off next word from input line */ parse() { unsigned char *tmptr, *tabptr; tmptr = inptr; for(tabptr = vocabulary; *tabptr; ) { for(inptr = tmptr; *inptr == *tabptr; ++inptr) ++tabptr; if(((128 + *tabptr) == *inptr++) && isterm(*inptr)) { skip_blank(); return *++tabptr; } else { inptr = tmptr; while(!(*tabptr++ & 0x80)); ++tabptr; } } fputs("I don't know the word '",stdout); while(!isterm(*inptr)) putc(*inptr++, stdout); message("'."); skip_blank(); return 0; } /* prompt for and get a line from the terminal */ get_line(string) char *string; { char chr, *ptr; do { fputs(string, stdout); inptr = ptr = inbuf; while((chr = getc(stdin)) != '\n') *ptr++ = chr; *ptr = 0; } while(!skip_blank()); } /* give description of an object, type=0 specifies inventory type description */ describe(object,table) unsigned object; char *table[]; { char *ptr, *ptr1; register unsigned pvalue; ptr = table[object]; pvalue = prop[object] + 1; while((--pvalue) && (*ptr)) { ptr1 = ptr; while((*ptr) && ('|' != *ptr++)); } if(!*ptr) ptr = ptr1; /* no special description */ while((*ptr) && ('|'!=*ptr)) putc(*ptr++, stdout); putc('.', stdout); putc('\n', stdout); } /* get full filename from single name, and open */ fileopen(filnam, opt) char *filnam, *opt; { register char *ptr, *ptr1; char filbuf[30]; ptr = filbuf; if(ptr1 = dirptr) { while(*ptr = *ptr1++) ++ptr; *ptr++ = '\\'; } while(*ptr = *filnam++) ++ptr; return fopen(filbuf, opt); } /* read in data file */ read_data_file(fname) char *fname; { unsigned i, j; char chr; fp = fileopen(fname,"rbvq"); i = 0; while((chr = getc(fp)) >= 0) { if(!chr) ftell(fp, &j, &places[i++]); } } /* determine if a location is dark */ isdark(locn) unsigned locn; { if(locn < DARK) return 0; if(!prop[0]) return 1; if(location[0] == locn) return 0; if((!location[0]) && (locn == current_loc)) return 0; return 1; } /* determine if object is here, complain if not */ have_object(obj) char obj; { if(!ishere(obj)) { message("I see no such object here."); return 0; } else return 1; } /* determine if an object is here */ ishere(obj) char obj; { return (location[obj] == 0) | (location[obj] == current_loc); } /* look at a location, and describe it */ look(locn) unsigned locn; { unsigned i; char chr, *eptr1, *eptr2; static char code1[] = { 54, 126, 99, 72, 12, 213, 99, 0 }, code2[] = { 77, 118, 41, 123, 18, 0 }; if(isdark(locn)) /* he can't see */ message("It is now pitch dark - if you procede, you will likely fall into a pit!"); else { fseek(fp, 0, places[locn], 0); eptr1 = eptr2 = ""; while((chr = getc(fp)) > 0) { if(!*eptr1) eptr1 = code1; if(!*eptr2) eptr2 = code2; chr ^= *eptr1++ ^ *eptr2++ ^ locn; putc(chr & 0x7f, stdout); } /* decribe doors if any */ for(i=0; i<6; ++i) if((travel[locn][i] >> 13) == 1) describe_door((travel[locn][i] >> 8) & 0x1f); /* describe dead monsters if any */ for(i=0; i < MONSTERS; ++i) if((monster_loc[i] == current_loc) && (monster_hits[i] <= 0)) message(dead_monster[i]); /* describe objects present */ for(i=0; i < OBJECTS; ++i) if(location[i] == locn) describe(i,l_descriptions); } /* give long description */ } /* describe a door */ describe_door(d) char d; { register char chr, *ptr; ptr = doors[d]; if(door_stat[d]) while('|' != *ptr++); while((chr=*ptr++) && ('|' != chr)) putc(chr,stdout); putc('.', stdout); putc('\n',stdout); } /* move the poor sap, passed is driection (0-5) */ move(dir) char dir; { unsigned new_loc, value; if(!(new_loc = travel[current_loc][dir])) { message(can_not_move); return 0; } old_loc = current_loc; if(new_loc & 0xff00) { /* conditions on move */ value = (new_loc >> 8) & 0x1f; switch(new_loc >> 13) { case 1 : /* door */ if(!door_stat[value]) { message(can_not_move); describe_door(value); return 0; } break; case 2 : /* has to have an object */ if(location[value]) { message("Something is preventing you from entering the passage."); return 0; } break; case 3 : /* has to not have an object */ if(!location[value]) { message(too_big); return 0; } break; case 4 : /* object must have prop 0 */ if(prop[value]) { message("Not implemented yet"); return 0; } break; case 5 : /* object must have prop 1 */ if(prop[value] != 1) { message("Not implemented yet"); return 0; } break; case 6 : /* special condition code */ if(!special_condition(value)) return 0; break; case 7 : /* special action as he moves */ current_loc = new_loc & 0xff; /* move him first incase he dies */ if(!special_action(value)) look(current_loc); return 1; } } /* all ok, move him now */ look(current_loc = new_loc & 0xff); return 1; } /* evaluate special conditions */ special_condition(cond) unsigned cond; { switch(cond) { case 0 : /* must be empty handed */ if(carry) { message(too_big); return 0; } break; case 1 : /* 10 percent probable */ if(4000 < random()) { special_action(1); /* lost message */ return 0; } break; case 2 : /* needs rope at current loc */ if(location[2] != current_loc) { message("The passage looks unsafe, you would surely fall."); return 0; } break; default : message("Bad special condition"); } return 1; } /* perform special actions as he moves return true indicates */ /* that no description of the new location should be given */ special_action(act) unsigned act; { unsigned temp; switch(act) { case 0 : /* forgets where he was */ old_loc = 0; break; case 1 : /* display "lost" message */ message("You have crawled around the rocks, and found yourself back in the main passage."); return 1; case 2 : /* arrow trap */ if(18000 > (temp = random())) { message("As you walk down the passage, tiny arrows fire at you from"); printf("little holes in the wall. %u of them get you - OUCH.\n", temp = (temp & 15) + 1); if((hits -= temp) <= 0) { die(); return 1; } } break; case 3 : /* enters wizards room */ monster_loc[11] = 174; /* wizard will enter shortly */ break; default : message("bad special action"); } return 0; } /* determine if noun is an object */ isobject(noun) unsigned noun; { if((noun < 100) || (noun > 199)) { message("I don't know of such a thing."); return -1; } else return noun - 100; } /* display message */ message(string) char *string; { fputs(string,stdout); putc('\n',stdout); } /* display ok message */ ok() { message("Ok"); } /* display not here message */ not_here() { message("I see nothing to do that to here."); } /* verify that word is in a given range */ test_range(word,r1,r2) unsigned word, r1, r2; { if(!word) { message("Please specifiy what you want to do it to."); return 0; } if((word < r1) || (word > r2)) { message("I don't know how to do that to the object you specified."); return 0; } return 1; } /* kill the poor sucker */ die() { unsigned i; for(i=0; i<OBJECTS; ++i) /* first, drop things when dead */ if(!location[i]) location[i] = current_loc; carry = 0; for(i=0; i < MONSTERS; ++i) /* release monsters */ if(monster_loc[i] == -1) monster_loc[i] = monster_start[i]; hits = STARTING_HITS; fputs(diemsgs[died], stdout); get_line("?"); if(*inptr == 'y') { message(resmsgs[died]); if(3 == ++died) /* force end of game */ end_game(); look(current_loc); } else end_game(); } /* calculate score */ calculate_score() { unsigned i, score; score = 0; for(i=20; i < OBJECTS; ++i) /* first give points for safely got treasure */ if(location[i] == 4) score += 10; for(i=0; i < MONSTERS; ++i) /* now give points for killing monsters */ if(monster_hits[i] <= 0) score += (i + 1); score += deep; /* add amount of cave explored */ score -= 10 * died; /* dock him if he died */ if((location[35] == 4) && (!prop[35])) /* give him more for not busting vase */ score += EXTRA_POINTS; return score; } /* finish off game, and quit */ end_game() { int score, max_score, i; max_score = ((10 * (OBJECTS - 20)) + (LOCS-1)) + EXTRA_POINTS; for(i=0; i < MONSTERS; ++i) max_score += (i+1); fclose(fp); if(score < 0) score = 0; printf("You have ended your game with a score of %d out of\n",score = calculate_score()); printf("a possible total of %u points, using %u turns.\n",max_score,turns); message(ranks[(score * 9) / max_score]); exit(0); } /* * Generate a "random" number */ random() { return seed = (seed * 13709) + 13849; }